home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_02_10
/
2n10050a
< prev
next >
Wrap
Text File
|
1991-01-27
|
7KB
|
184 lines
.386p
;---------------------------------------------------------------;
; CPU_Type determines the CPU type in the system. ;
;---------------------------------------------------------------;
; Written by: ;
; Robert Collins ;
; 215 Avenida Espana ;
; San Jose, CA 95139 ;
;---------------------------------------------------------------;
; Input: None ;
; Output: AX = CPU type ;
; 0 = 8086/8088 ;
; 1 = 80186/80188 ;
; 2 = 80286 ;
; 3 = 80386 ;
; 4 = 80486 ;
; FFFF = Unknown CPU type ;
; Register(s) modified: AX, BX, CX, EDX ;
;---------------------------------------------------------------;
; Macro definitions ;
;---------------------------------------------------------------;
; 80486 instruction macro -- because MASM 5.1 doesn't support ;
; the 80486! ;
;---------------------------------------------------------------;
XADD macro ;
db 0fh,0C0h,0D2h ; 80486 instruction macro ;
ENDM ;
;
;
;---------------------------------------------------------------;
CPU_Type proc near ;
;---------------------------------------------------------------;
; Determine the CPU type by testing for differences in the CPU ;
; in the system. ;
;---------------------------------------------------------------;
; To determine if we are a 8086/8088, or 80186/80188, test the
; value of SP after it is placed on the stack. The algorithm
; for "PUSH SP" differs from 8086/80186 to 80286+. The
; algorithm difference is as follows:
;
; 8086/80186 80286+
; { {
; SP = SP - 2 TEMP = SP
; SS:SP = SP SP = SP - 2
; } SS:SP = TEMP
; }
;
; Thus for the 8086/80186, the value of SP that gets pushed on
; the stack is the value after SP is decremented. Hence, the
; value on the stack does not reflect the value of SP before the
; "PUSH" instruction. Therefore, all we have to do to
; categorize the CPU as 8086/8088 or 80186/80188 is to "PUSH SP"
; and compare the value on the stack image to the value in SP.
;---------------------------------------------------------------
xor ax,ax ; clear CPU type return register
push sp ; save SP on stack to look at
pop bx ; get SP saved on stack
cmp bx,sp ; if 8086/8088 these values will
; differ
jz short @Not_8086 ; nope, must be other CPU type
;---------------------------------------------------------------
; If this test passes, then we need some other means to differ-
; entiate between 8088/8088 and 80186/80188. This method I will
; use comes from "80186/188, 80C186/C188 Hardware Reference
; Manual" from Intel, PN# 270788, page A-2: "When a word write
; is performed at offset FFFFh in a segment, the 8086 will write
; one byte at offset FFFFh, and the other at offset 0, while an
; 80186 family processor will write one byte at offset FFFFh,
; and the other at offset 10000h (one byte beyond the end of the
; segment).
;---------------------------------------------------------------
; Before we can blast a value out to FFFFh, we must save
; anything there, so we don't crash anybody else's data.
;---------------------------------------------------------------
push es
mov bx,ds ; get original DS
inc bx
mov es,bx
mov bl,ds:[0] ; get byte @ 0
mov bh,es:[0fff0h] ; get byte @ 10000h
mov ds:[0ffffh],0aaaah ; write signature at
; test location
cmp byte ptr ds:[0],0aah ; 8086?
mov ds:[0],bl ; restore original value
mov es:[0fff0h],bh
pop es
je short CPU_8086_Exit
inc ax
jmp short CPU_8086_Exit
;---------------------------------------------------------------
; When we get here, we know that we aren't a 8086/80186. And
; since all subsequent processors will trap invalid opcodes via
; INT6, we will determine which CPU we are by trapping an
; invalid opcode.
; We are an 80486 if: XADD DX,DX executes correctly
; 80386 if: MOV EDX,CR0 executes correctly
; 80286 if: SMSW DX executes correctly
;---------------------------------------------------------------
; Setup INT6 handler
;---------------------------------------------------------------
@Not_8086:
enter 4,0 ; create stack frame
mov word ptr INT6,offset INT6_handler
mov INT6+2,cs
call set_INT6_vector ; set pointer for INT6 handler
mov ax,4 ; initialize CPU flag=4 (80486)
xor cx,cx ; initialize semaphore
;---------------------------------------------------------------
; Now, try and determine which CPU we are by executing invalid
; opcodes. The instructions I chose to invoke invalid opcodes,
; are themselves rather benign. In each case, the chosen
; instruction modifies the DX register, and nothing else. No
; system parameters are changed, e.g. protected mode, or other
; CPU dependant features.
;---------------------------------------------------------------
; The 80486 instruction 'XADD' xchanges the registers, then adds
; them. The exact syntax for a '486 compiler would be:
; XADD DX,DX.
;---------------------------------------------------------------
XADD ;DX,DX ; 80486
jcxz CPU_exit
dec ax ; set 80386 semaphore
inc cx ; CX=0
;---------------------------------------------------------------
; For a description on the effects of the following instructions,
; look in the Intel Programmers Reference Manual's for the 80186,
; 80286, or 80386.
;---------------------------------------------------------------
mov edx,cr0 ; 80386
jcxz CPU_exit
dec ax ; set 80286 semaphore
inc cx ; CX=0
smsw dx ; 80286
jcxz CPU_exit
sub ax,3 ; set UNKNOWN_CPU semaphore
CPU_exit:
call set_INT6_vector
leave
CPU_8086_exit:
ret
;---------------------------------------------------------------
; Set the INT6 vector by exchanging it with the one currently on
; the stack.
;---------------------------------------------------------------
set_INT6_vector:
push ds
push ABS0 ; save interrupt vector segment
pop ds ; make DS=INT vector segment
ASSUME DS:ABS0
mov dx,word ptr ds:INT_6 ; get offset of INT6
xchg INT6,dx ; set new INT6 offset
mov word ptr ds:INT_6,dx
mov dx,word ptr ds:INT_6[2] ; get segment of INT6
xchg INT6+2,dx ; set new INT6 segment
mov word ptr ds:INT_6[2],dx
pop ds ; restore register
ret ; split
ASSUME DS:_TEXT
;---------------------------------------------------------------
; INT6 handler sets a semaphore (CX=FFFF) and adjusts the return
; address to point past the invalid opcode.
; [BP]
;---------------------------------------------------------------
INT6_handler:
enter 0,0 ; create new stack frame
dec cx ; make CX=FFFF
add word ptr ss:[bp][2],3 ; point past invalid
; opcode
leave
iret
CPU_Type endp